package com.stylefeng.guns.core.util.appSecure;

import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * Description: 文件或字符串hash值计算
 *
 * @author
 * @version 2.0
 * @since 2017/5/9
 */
class Hash {
    static final String MD5  = "MD5";
    static final String SHA1 = "SHA-1";

    private static final Object LOCK = new Object();

    private static final byte[] HEX_CHAR_TABLE = {
            (byte) '0', (byte) '1', (byte) '2', (byte) '3',
            (byte) '4', (byte) '5', (byte) '6', (byte) '7',
            (byte) '8', (byte) '9', (byte) 'A', (byte) 'B',
            (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F'
    };

    private static String convertToHex(byte[] raw) {
        StringBuilder sb = new StringBuilder(raw.length * 2);
        for (byte b : raw) {
            int v = b & 0xFF;
            sb.append((char) HEX_CHAR_TABLE[v >>> 4]);
            sb.append((char) HEX_CHAR_TABLE[v & 0xF]);
        }
        return sb.toString();
    }

    public static byte[] hash(byte[] bytes, String algorithm) {
        synchronized (LOCK) {
            try {
                MessageDigest md = MessageDigest.getInstance(algorithm);
                md.update(bytes, 0, bytes.length);
                return md.digest();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            return new byte[0];
        }
    }

    public static byte[] hash(File file, String algorithm) {
        synchronized (LOCK) {
            try {
                MessageDigest md = MessageDigest.getInstance(algorithm);
                int BUFFER = 1 << 16;
                FileInputStream fio = new FileInputStream(file);
                FileChannel fc = fio.getChannel();
                ByteBuffer buffer = ByteBuffer.allocate(BUFFER);
                while (fc.read(buffer) != -1) {
                    buffer.flip();
                    md.update(buffer);
                    buffer.clear();
                }
                fio.close();
                return md.digest();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return new byte[0];
        }
    }

    public static String make(byte[] bytes, String algorithm) {
        return convertToHex(hash(bytes, algorithm));
    }

    public static String make(File file, String algorithm) {
        return convertToHex(hash(file, algorithm));
    }
}
